package com.aabte.springcloudlearn.ribbonhystrixcustomerdemo.service;

import com.aabte.springcloudlearn.common.beans.User;
import com.aabte.springcloudlearn.common.utils.CommonMethod;
import com.aabte.springcloudlearn.ribbonhystrixcustomerdemo.hystrix.UserCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import com.netflix.hystrix.HystrixCommandProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.ObservableExecutionMode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import rx.Observable;
import rx.Subscriber;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Daniel
 */
@Slf4j
@Service
public class ObservableCustomerService {

    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(
            fallbackMethod = "fallbackForUseObserveByAnnotation",
            // 表示使用observe模式来执行（默认）
            // observableExecutionMode = ObservableExecutionMode.EAGER
            // 表示使用toObservable模式来执行
            observableExecutionMode = ObservableExecutionMode.LAZY
    )
    public Observable<User> useObserveByAnnotation(Long userId) {
        log.info("Start observeByAnnotation. userId: {}", userId);

        Map<String, Object> urlParams = new HashMap<>(1);
        urlParams.put("userId", userId);

        Observable<User> userObservable = Observable.create(new Observable.OnSubscribe<User>() {
            @Override
            public void call(Subscriber<? super User> subscriber) {
                log.info("Start OnSubscribe.call method. urlParams: {}", urlParams);
                if (!subscriber.isUnsubscribed()) {
                    User user = restTemplate.getForObject("http://hello-service/user/{userId}", User.class, urlParams);
                    subscriber.onNext(user);
                    subscriber.onCompleted();
                }
                log.info("End OnSubscribe.call method.");
            }
        });

        log.info("End observeByAnnotation.");
        return userObservable;
    }

    /**
     * {@link #useObserveByAnnotation} 降级方法
     */
    public User fallbackForUseObserveByAnnotation(Long userId, Throwable e) {
        log.warn("Start fallbackForUseObserveByAnnotation. userId: {}, ex: {}", userId, CommonMethod.getErrorStack(e));
        return null;
    }


    /**
     * 使用自定义{@link com.netflix.hystrix.HystrixCommand#observe()}方法，实现订阅
     */
    public Observable<User> useObserveRequestGetUserById(Long userId) {
        log.info("Start useObserveRequestGetUserById. userId: {}", userId);

        UserCommand userCommand = new UserCommand(com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(
                HystrixCommandGroupKey.Factory.asKey(""))
                .andCommandPropertiesDefaults(
                        HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(5000)),
                restTemplate,
                userId);

        Observable<User> userObservable = userCommand.observe();
        log.info("End useObserveRequestGetUserById.");
        return userObservable;
    }

    /**
     * 使用自定义{@link com.netflix.hystrix.HystrixCommand#toObservable()}方法，实现订阅
     */
    public Observable<User> useToObservableRequestGetUserById(Long userId) {
        log.info("Start useToObservableRequestGetUserById. userId: {}", userId);

        UserCommand userCommand = new UserCommand(com.netflix.hystrix.HystrixCommand.Setter.withGroupKey(
                HystrixCommandGroupKey.Factory.asKey(""))
                .andCommandPropertiesDefaults(
                        HystrixCommandProperties.Setter().withExecutionTimeoutInMilliseconds(5000)),
                restTemplate,
                userId);

        Observable<User> userObservable = userCommand.toObservable();
        log.info("End useToObservableRequestGetUserById.");
        return userObservable;
    }


}
